package org.balthie.demo.sum.misc.direct;



import java.beans.PropertyDescriptor;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;

/**
* @author Hebojin
* @createTime 2022年8月12日 下午4:16:16
* @Description 类描述
*/

public class FormatLiunxSmapsTool
{
    /**
     * 放在default package
     * 
     * 依赖easyexcel.jar
     * <dependency>
     * <groupId>com.alibaba</groupId>
     * <artifactId>easyexcel</artifactId>
     * <version>3.1.0</version>
     * </dependency>
     * 
     */
    
    public static void main(String[] args) throws Exception
    {
        final String inputTxt = "H:\\dump\\dp\\cms_dump_0817\\agent\\smaps_cms_0817.txt";
        final String outputExcel = inputTxt.replace(".txt", ".xlsx");
        FormatLiunxSmapsTool.converSmapsTxtToExcel(inputTxt, outputExcel);
    }
    
    /**
     * Smaps.txt转换成Excel格式
     * 
     * @author：Hebojin
     * @createTime ： 2022年8月15日 下午4:58:44
     * @param inputTxt
     * @param outputExcel
     * @throws Exception
     */
    public static void converSmapsTxtToExcel(String inputTxt, String outputExcel) throws Exception
    {
        System.out.println("---------Smaps.txt开始转换Excel格式-----");
        InputStreamReader read = null;
        final String pattern1 = "(\\S+)\\s+(\\d+)\\s+\\.*";// KernelPageSize: 4 kB
        final String pattern2 = "(\\S+)\\s+(.*)";// VmFlags: rd wr mr mw me ac sd
        Map<String, String> resultMap = new HashMap<String, String>(32);
        List<Smaps> list = new ArrayList<Smaps>(100);
        ExcelWriter writer = null;
        try
        {
            String encoding = "GBK";
            File file = new File(inputTxt);
            if(!file.isFile() && !file.exists())
            { // 判断文件是否存在
                System.out.println("找不到指定的文件");
                return;
            }
            
            // 设置写Excel
            writer = EasyExcel.write(outputExcel, Smaps.class).build();
            WriteSheet writeSheet = EasyExcel.writerSheet("Smaps").build();
            
            int LineNum = 0;
            int mod = 0;
            
            read = new InputStreamReader(new FileInputStream(file), encoding);// 考虑到编码格式
            @SuppressWarnings("resource")
            BufferedReader bufferedReader = new BufferedReader(read);
            String lineTxt = null;
            while ((lineTxt = bufferedReader.readLine()) != null)
            {
                mod = LineNum % 21;// smap.txt 一个subject有21个元素
                if(mod == 0)
                {
                    resultMap.put("Subject", lineTxt);
                }
                else if(mod == 20)// 第21个元素没有数字值
                {
                    FormatLiunxSmapsTool.prasingSmapsLineStr(lineTxt, pattern2, resultMap);
                    // 完成第21个元素解析转换成resultMap后，再转换成Smaps对象，并加入集合
                    list.add(FormatLiunxSmapsTool.converToSmaps(resultMap));
                }
                else
                {// 第2-20个元素提取数字值
                    FormatLiunxSmapsTool.prasingSmapsLineStr(lineTxt, pattern1, resultMap);
                }
                
                if(list.size() == 100)// 每100行写文件
                {
                    writer.write(list, writeSheet);
                    list = new ArrayList<Smaps>(100);
                }
                LineNum++;
            }
            
            writer.write(list, writeSheet);// 续写文件
            System.out.println("文件转换完毕：" + outputExcel);
            if(LineNum % 21 != 0)
            {
                System.out.println("已读完" + LineNum + 1 + "行,但该行不是Smap对象的最后一个元素，请核实");
            }
        }
        catch (Exception e)
        {
            System.out.println("读取文件内容出错");
            throw e;
        }
        finally
        {
            if(writer != null)
            {
                writer.close();
            }
            if(read != null)
            {
                try
                {
                    read.close();
                }
                catch (IOException e)
                {
                    System.out.println("关闭文件内容出错");
                    e.printStackTrace();
                }
            }
        }
        System.out.println("-----------end------------");
    }
    
    /**
     * 解析Smaps.txt行
     * 
     * @author：Hebojin
     * @createTime ： 2022年8月15日 下午4:55:27
     * @param str
     * @param pattern
     * @param result
     * @throws Exception
     */
    private static void prasingSmapsLineStr(String str, String pattern, Map<String, String> result) throws Exception
    {
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(str);
        if(m.find())
        {
            result.put(m.group(1).replace(":", ""), m.group(2));
        }
        else
        {
            throw new Exception("文件格式发生变更，不能解析！");
        }
    }
    

    /**
     * 利用动态反射转换成Smaps对象，Map的key值为Smaps对象的私有变量字段
     * 
     * @author：Hebojin
     * @createTime ： 2022年8月15日 下午4:56:46
     * @param map
     * @return
     * @throws Exception
     */
    private static Smaps converToSmaps(Map<String, String> map) throws Exception
    {
        Field[] fields = Smaps.class.getDeclaredFields();
        if(fields.length != map.keySet().size())
        {
            throw new Exception("Smaps类属性字段数和Smaps.txt对象字段数不一致,请检查文件格式是否发生变化");
        }
        
        Smaps obj = Smaps.class.newInstance();
        for(Field filed : fields)
        {
            // System.out.println(filed.getName());
            if(!map.containsKey(filed.getName()))
            {
                throw new Exception("Smaps类属性字段" + filed.getName() + "不存在Smaps.txt,请检查文件格式是否发生变化");
            }
            PropertyDescriptor pd = new PropertyDescriptor(filed.getName(), Smaps.class);
            Method wM = pd.getWriteMethod();
            if(pd.getPropertyType() == int.class)
            {
                wM.invoke(obj, Integer.parseInt(map.get(filed.getName())));
            }
            else
            {
                wM.invoke(obj, map.get(filed.getName()));
            }
        }
        
        return obj;
    }
    

    public static class Smaps
    {
        /**
         * 利用反射调用，把cat /proc/[pid]/smaps > smaps.txt 的字段映射到此类属性
         * 故类变量的字段值，与smaps.txt的字段保持一致
         */
        private String Subject;
        
        private int Size;
        
        private int KernelPageSize;
        
        private int MMUPageSize;
        
        private int Rss;
        
        private int Pss;
        
        private int Shared_Clean;
        
        private int Shared_Dirty;
        
        private int Private_Clean;
        
        private int Private_Dirty;
        
        private int Referenced;
        
        private int Anonymous;
        
        private int LazyFree;
        
        private int AnonHugePages;
        
        private int ShmemPmdMapped;
        
        private int Shared_Hugetlb;
        
        private int Private_Hugetlb;
        
        private int Swap;
        
        private int SwapPss;
        
        private int Locked;
        
        private String VmFlags;
        
        public Smaps()
        {
            // TODO Auto-generated constructor stub
        }
        
        public String getSubject()
        {
            return Subject;
        }
        
        public void setSubject(String subject)
        {
            Subject = subject;
        }
        
        public int getSize()
        {
            return Size;
        }
        
        public void setSize(int size)
        {
            Size = size;
        }

        public int getKernelPageSize()
        {
            return KernelPageSize;
        }
        
        public void setKernelPageSize(int kernelPageSize)
        {
            KernelPageSize = kernelPageSize;
        }
        
        public int getMMUPageSize()
        {
            return MMUPageSize;
        }
        
        public void setMMUPageSize(int mMUPageSize)
        {
            MMUPageSize = mMUPageSize;
        }
        
        public int getRss()
        {
            return Rss;
        }
        
        public void setRss(int rss)
        {
            Rss = rss;
        }
        
        public int getPss()
        {
            return Pss;
        }
        
        public void setPss(int pss)
        {
            Pss = pss;
        }
        
        public int getShared_Clean()
        {
            return Shared_Clean;
        }
        
        public void setShared_Clean(int shared_Clean)
        {
            Shared_Clean = shared_Clean;
        }
        
        public int getShared_Dirty()
        {
            return Shared_Dirty;
        }
        
        public void setShared_Dirty(int shared_Dirty)
        {
            Shared_Dirty = shared_Dirty;
        }
        
        public int getPrivate_Clean()
        {
            return Private_Clean;
        }
        
        public void setPrivate_Clean(int private_Clean)
        {
            Private_Clean = private_Clean;
        }
        
        public int getPrivate_Dirty()
        {
            return Private_Dirty;
        }
        
        public void setPrivate_Dirty(int private_Dirty)
        {
            Private_Dirty = private_Dirty;
        }
        
        public int getReferenced()
        {
            return Referenced;
        }
        
        public void setReferenced(int referenced)
        {
            Referenced = referenced;
        }
        
        public int getAnonymous()
        {
            return Anonymous;
        }
        
        public void setAnonymous(int anonymous)
        {
            Anonymous = anonymous;
        }
        
        public int getLazyFree()
        {
            return LazyFree;
        }
        
        public void setLazyFree(int lazyFree)
        {
            LazyFree = lazyFree;
        }
        
        public int getAnonHugePages()
        {
            return AnonHugePages;
        }
        
        public void setAnonHugePages(int anonHugePages)
        {
            AnonHugePages = anonHugePages;
        }
        
        public int getShmemPmdMapped()
        {
            return ShmemPmdMapped;
        }
        
        public void setShmemPmdMapped(int shmemPmdMapped)
        {
            ShmemPmdMapped = shmemPmdMapped;
        }
        
        public int getShared_Hugetlb()
        {
            return Shared_Hugetlb;
        }
        
        public void setShared_Hugetlb(int shared_Hugetlb)
        {
            Shared_Hugetlb = shared_Hugetlb;
        }
        
        public int getPrivate_Hugetlb()
        {
            return Private_Hugetlb;
        }
        
        public void setPrivate_Hugetlb(int private_Hugetlb)
        {
            Private_Hugetlb = private_Hugetlb;
        }
        
        public int getSwap()
        {
            return Swap;
        }
        
        public void setSwap(int swap)
        {
            Swap = swap;
        }
        
        public int getSwapPss()
        {
            return SwapPss;
        }
        
        public void setSwapPss(int swapPss)
        {
            SwapPss = swapPss;
        }
        
        public int getLocked()
        {
            return Locked;
        }
        
        public void setLocked(int locked)
        {
            Locked = locked;
        }
        
        public String getVmFlags()
        {
            return VmFlags;
        }
        
        public void setVmFlags(String vmFlags)
        {
            VmFlags = vmFlags;
        }
        
        @Override
        public String toString()
        {
            return "Smaps [Subject="
                    + Subject + ", Size=" + Size + ", KernelPageSize=" + KernelPageSize + ", MMUPageSize=" + MMUPageSize
                    + ", Rss=" + Rss + ", Pss=" + Pss + ", Shared_Clean=" + Shared_Clean + ", Shared_Dirty=" + Shared_Dirty
                    + ", Private_Clean=" + Private_Clean + ", Private_Dirty=" + Private_Dirty + ", Referenced=" + Referenced
                    + ", Anonymous=" + Anonymous + ", LazyFree=" + LazyFree + ", AnonHugePages=" + AnonHugePages
                    + ", ShmemPmdMapped=" + ShmemPmdMapped + ", Shared_Hugetlb=" + Shared_Hugetlb + ", Private_Hugetlb="
                    + Private_Hugetlb + ", Swap=" + Swap + ", SwapPss=" + SwapPss + ", Locked=" + Locked + ", VmFlags=" + VmFlags
                    + "]";
        }
        
        
    }
}
